/*
 * test.c
 * Test driver!
 */
#include <bwio.h>
#include "common.h"
#include <ts7200.h>
#include "evio.h"

static struct iobuf b;
static struct txq q;
static struct io i, j;

int test(const char* msg, int condition) {
  if (!condition) {
    bwprintf( COM2, "%s\r\n", msg );
  }
  return condition;
}

void init() {
  bwsetspeed( COM2, 115200 );
  bwsetfifo( COM2, OFF );
  bwprintf( COM2, "test.elf v (0.)*1 \r\n" );
  bwprintf( COM2, "Evan Stratford\r\n\r\n" );
}

int main(int argc, char* argv[]) {
  init();
  
  // test init queue
  bwprintf( COM2, "[ queue ]\r\n" );
  iobuf_init( &b );
  if (!test("0 error in iobuf_empty()!", iobuf_empty( &b ))) return 1;
  
  // test enqueue, dequeue once
  i.b1 = 'C'; i.b2 = 'S';
  if (!test("1 insert shouldn't fail!", iobuf_enqueue( &b, i ))) return 1;
  if (!test("2 error in iobuf_empty()!", !iobuf_empty( &b ))) return 1;
  if (!test("3 insert doesn't set size properly!", b.size == 1)) return 1;
  if (!test("4 insert doesn't update back properly!", b.back == 1)) return 1;
  if (!test("5 insert shouldn't touch front!", b.front == 0)) return 1;
  if (!test("6 remove shouldn't fail!", iobuf_dequeue( &b, &j ))) return 1;
  if (!test("7 error in iobuf_empty()!", iobuf_empty( &b ))) return 1;
  if (!test("8 remove doesn't set size properly!", b.size == 0)) return 1;
  if (!test("9 remove shouldn't touch back!", b.back == 1)) return 1;
  if (!test("10 remove doesn't update front properly!", b.front == 1)) return 1;
  if (!test("11 remove should retrieve same io!",
      (i.b1 == j.b1) && (i.b2 == j.b2))) return 1;

  // test dequeue on empty
  if (!test("12 remove should fail!", !iobuf_dequeue( &b, &j ))) return 1;

  // fill the queue
  int n;
  for (n = 0; n < 16; n++) {
    if (!test("13 insert shouldn't fail!", iobuf_enqueue( &b, i ))) return 1;
  }
  if (!test("13.5 size not at correct value!", b.size == 16)) return 1;
  if (!test("14 insert should fail!", !iobuf_enqueue( &b, i ))) return 1;
  if (!test("15 size not at correct value!", b.size == 16)) return 1;

  // remove 7, add 3
  for (n = 0; n < 7; n++) iobuf_dequeue( &b, &j );
  for (n = 0; n < 3; n++) iobuf_enqueue( &b, i );
  if (!test("16 size!", b.size == 12)) return 1;
  if (!test("17 back!", b.back == 4)) return 1;
  if (!test("18 front!", b.front == 8)) return 1;
  bwprintf( COM2, "ok\r\n" );

  // init heap
  bwprintf( COM2, "[ heap ]\r\n" );
  txq_init( &q );
  if (!test("0 error in txq_empty()!", txq_empty( &q ))) return 1;
  
  // pop on empty, should fail
  if (!test("1 peek should fail!", !txq_top( &q, &j ))) return 1;
  if (!test("1.5 size!", q.size == 0)) return 1;
  if (!test("2 remove should fail!", !txq_pop( &q ))) return 1;
  if (!test("2.5 size!", q.size == 0)) return 1;
  
  // insert, then remove
  i.data = 10;
  if (!test("3 insert shouldn't fail!", txq_push( &q, i ))) return 1;
  if (!test("4 size!", q.size == 1)) return 1;
  if (!test("5 error in txq_empty()!", !txq_empty( &q ))) return 1;
  if (!test("6 top shouldn't fail!", txq_top( &q, &j ))) return 1;
  if (!test("7 pop shouldn't fail!", txq_pop( &q ))) return 1;
  if (!test("8 top should retrieve same io!", i.data == j.data)) return 1;
  if (!test("8.5 error in txq_empty()!", txq_empty( &q ))) return 1;

  // heap property
  i.data = 6; txq_push( &q, i );
  i.data = 13; txq_push( &q, i );
  i.data = 42; txq_push( &q, i );
  i.data = 1; txq_push( &q, i );
  i.data = 19; txq_push( &q, i );
  i.data = 7; txq_push( &q, i );
  i.data = 14; txq_push( &q, i );
  i.data = 3; txq_push( &q, i );
  i.data = 3; txq_push( &q, i );
  if (!test("9 size!", q.size == 9)) return 1;
  for (n = 1; n < 9; n++) {
    if (!test("9 heap property fails!",
        q.q[n].data >= q.q[(n-1)/2].data)) return 1;
  }
  bwprintf( COM2, "ok\r\n" );

  return 0;
}
